"""Pysv commands"""

__license__ = """
Copyright (c) 2006 Michael Twomey

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

import subprocess

from elementtree import ElementTree

from sv import utils

class Commands(object):
    def __init__(self):
        self.commands = {}
    
    def register(self, name):
        """Register decorator"""
        def decorator(fn):
            self.commands[name] = fn
            return fn
        return decorator
    
    def execute(self, command, options, args):
        return self.commands[command](options, args)
    
    def usage(self):
        help_text = ["%prog command [command args]\n", "Commands:\n"]
        for command in sorted(self.commands.values()):
            help_text.append(command.__doc__)
        return "\n".join(help_text)

commands = Commands()
register = commands.register

@register("help")
def help(options, args):
    """help
    Prints out help.
    """
    if len(args) > 0:
        command = args[0]
        print commands.commands[command].__doc__
    else:
        print commands.usage()

@register("branches")
def branches(options, args):
    """branches
    Lists branches for the current location.
    """
    prefix = utils.get_prefix()

    cmd = ["svn", "list", "--xml", "%s/branches" % prefix]
    buf = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
    root = ElementTree.parse(buf)
    
    entries = []
    for entry in root.findall("/list/entry"):
        entries.append(entry.find("name").text)
    entries.sort()
    for entry in entries:
        print entry

@register("branch")
def branch(options, args):
    """branch [branch]
    Creates a new branch in the given project.
    e.g. branch foo-issue123
    """
    prefix = utils.get_prefix()
    branchname = args[0]
    info = {
        "project": prefix,
        "branch": branchname,
    }
    cmd = ["svn", "cp", 
        "-m Creating branch %(branch)s"  % info,
        "%(project)s/trunk/"  % info,
        "%(project)s/branches/%(branch)s" % info,
    ]
    print " ".join(cmd)
    subprocess.call(cmd)

@register("switch")
def switch(options, args):
    """switch [branch]
    Switches the current directory to the given branch
    e.g. switch foo-issue123
    
    trunk is a special case which will switch back to the trunk.
    """
    prefix = utils.get_prefix()
    branch = args[0]
    print "svn up"
    subprocess.call(["svn", "up"])
    
    print "cleaning pyc"
    subprocess.call(["find", ".", "-name", "*.pyc", "-delete"])
    if branch == "trunk":
        cmd = ["svn", "switch", "%s/trunk/" % (prefix)]
    else:
        cmd = ["svn", "switch", "%s/branches/%s" % (prefix, branch)]
    print " ".join(cmd)
    subprocess.call(cmd)

# TODO use svn log to figure out the revisions to merge with, assuming only
# one merge ever occurs
@register("merge")
def merge(options, args):
    """merge [optional revisionspec] [branch]
    Merge changes from the branch into the current sandbox.
    e.g. merge mybranch
         merge 123:456 mybranch
    
    If you omit the revision spec it is calculated from the log. Multiple
    merges aren't handled by the revision spec calculation, so manually 
    specify the revisions.
    """
    if len(args) == 2:
        branch = args[1]
    else:
        branch = args[0]
    prefix = utils.get_prefix()
    branch = "%s/branches/%s" % (prefix, branch)
    
    if len(args) == 1:
        revisions = utils.get_revisions(branch)
        revisions = "%d:%d" % (revisions[0], revisions[-1])
    else:
        revisions = args[0]
    
    cmd = ["svn", "merge", "-r%s" % revisions, branch]
    print " ".join(cmd)
    subprocess.call(cmd)

@register("branchlog")
def branchlog(options, args):
    """branchlog [branch]
    Prints out the log for the branch.
    """
    prefix = utils.get_prefix()
    if len(args) == 0:
        branch = utils.get_branch()
    else:
        branch = args[0]
    branch = "%s/branches/%s" % (prefix, branch)
    subprocess.call(["svn", "log", "--stop-on-copy", branch])

logmsg_template = """%(msg)s
"""

@register("mergelog")
def mergelog(options, args):
    """mergelog [branch]
    Generates a template log message suitable for a marge
    """
    branchname = args[0]
    prefix = utils.get_prefix()
    branch = "%s/branches/%s" % (prefix, branchname)
        
    cmd = ["svn", "log", "--xml", "--stop-on-copy", branch]
    buf = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
    root = ElementTree.parse(buf)
    revisions = []
    # skip the first revision, that's the boring "created branch" one
    for logentry in root.findall("logentry")[:-1]:
        revisions.append(int(logentry.attrib["revision"]))
        info = dict(
            author = logentry.find("author").text,
            date = logentry.find("date").text,
            msg = logentry.find("msg").text,
        )
        print logmsg_template % info
    revisions.sort()
    print "Merged %d:%d from branch %s" % (revisions[0], revisions[-1], branchname)


@register("rmbranch")
def rmbranch(options, args):
    """rmbranch [branch]
    Remove the specified branch
    """
    prefix = utils.get_prefix()
    branch = "%s/branches/%s" % (prefix, args[0])
    if options.yes:
        cmd = ["svn", "rm", "-m Removing branch", branch]
    else:
        cmd = ["svn", "rm", branch]
    subprocess.call(cmd)
